#include "hal_rs485.h"
#include "hal_tty.h"
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>

#include "hk32c030xx.h"
#include "hk32c030xx_dma.h"
#include "hk32c030xx_gpio.h"
#include "hk32c030xx_uart.h"

#include "utils_fifo.h"
#include "FreeRTOS.h"
#include "portable.h"
#include "semphr.h"

static ring_buffer_t *rs485_ringbuf_send, *rs485_ringbuf_recv;/*收发缓冲区管理 ---------*/

static uint8_t rs485_dma_tx_buf[RS485_TXBUFFER_SIZE];/*DMA发送缓冲区 ---------*/
static uint8_t rs485_dma_rx_buf[RS485_RXBUFFER_SIZE];/*DMA接收缓冲区 ---------*/     
static SemaphoreHandle_t rs485_semap_;

static void rs485_gpio_init() {

	GPIO_InitTypeDef uart_io_struct;
	RCC_AHBPeriphClockCmd(RS485_UART_IO_RCU, ENABLE);
			
    GPIO_PinAFConfig(RS485_UART_IO_BASE, RS485_TX_PIN_SOURCE, GPIO_AF_3);
    GPIO_PinAFConfig(RS485_UART_IO_BASE, RS485_RX_PIN_SOURCE, GPIO_AF_3);
	
	uart_io_struct.GPIO_Mode = GPIO_Mode_AF;
	uart_io_struct.GPIO_Pin = RS485_UART_TX_PIN | RS485_UART_RX_PIN;
    uart_io_struct.GPIO_OType = GPIO_OType_PP;
    uart_io_struct.GPIO_Speed = GPIO_Speed_10MHz;
    uart_io_struct.GPIO_PuPd = GPIO_PuPd_UP;
	GPIO_Init(RS485_UART_IO_BASE, &uart_io_struct);
}

static void rs485_uart_init() {
	
	UART_InitTypeDef rs485_struct;

	RCC_APB1PeriphClockCmd(RS485_UART_RCU,ENABLE);

	UART_StructInit(&rs485_struct);
	rs485_struct.UART_BaudRate = RS485_BAUDRATE;
	rs485_struct.UART_WordLength = UART_WordLength_8b;
	rs485_struct.UART_Mode = UART_Mode_Rx | UART_Mode_Tx;
	rs485_struct.UART_Parity = UART_Parity_No;
	rs485_struct.UART_StopBits = UART_StopBits_1;
	
	UART_Init(RS485_UART_CORE, &rs485_struct);

	UART_DMACmd(RS485_UART_CORE,UART_DMAReq_Tx, ENABLE);
	UART_DMACmd(RS485_UART_CORE,UART_DMAReq_Rx, ENABLE);

    rs485_ringbuf_send = ring_buffer_create(RS485_TXFIFO_SIZE);
    rs485_ringbuf_recv = ring_buffer_create(RS485_RXFIFO_SIZE);
}

static void rs485_dma_init() {
    
	DMA_InitTypeDef dma_struct;	
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA, ENABLE);  
	
	DMA_DeInit(RS485_DMA_TX_CHANNEL);
    DMA_DeInit(RS485_DMA_RX_CHANNEL);
	
	dma_struct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    dma_struct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    dma_struct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    dma_struct.DMA_MemoryInc = DMA_MemoryInc_Enable;
    dma_struct.DMA_Mode = DMA_Mode_Normal;
    dma_struct.DMA_M2M = DMA_M2M_Disable;
		
	dma_struct.DMA_PeripheralBaseAddr = (uint32_t)(&RS485_UART_CORE->TDR);
	dma_struct.DMA_BufferSize = sizeof(rs485_dma_tx_buf);
	dma_struct.DMA_MemoryBaseAddr = (uint32_t)rs485_dma_tx_buf;
    dma_struct.DMA_DIR = DMA_DIR_PeripheralDST;  
	dma_struct.DMA_Priority = DMA_Priority_High;
    DMA_Init(RS485_DMA_TX_CHANNEL, &dma_struct);
	
	dma_struct.DMA_PeripheralBaseAddr = ((uint32_t)&RS485_UART_CORE->RDR);
	dma_struct.DMA_BufferSize = sizeof(rs485_dma_rx_buf);
    dma_struct.DMA_MemoryBaseAddr = (uint32_t)rs485_dma_rx_buf;
    dma_struct.DMA_DIR = DMA_DIR_PeripheralSRC;
    dma_struct.DMA_Priority = DMA_Priority_Low;
	dma_struct.DMA_Mode = DMA_Mode_Circular;
	DMA_Init(RS485_DMA_RX_CHANNEL, &dma_struct);
	
	DMA_ITConfig(RS485_DMA_RX_CHANNEL, DMA_IT_TC, ENABLE);    
	DMA_ITConfig(RS485_DMA_RX_CHANNEL, DMA_IT_HT, ENABLE);
	
	UART_Cmd(RS485_UART_CORE, ENABLE);
	DMA_Cmd(RS485_DMA_RX_CHANNEL,ENABLE); 
	
	NVIC_InitTypeDef rs485_nvic;
	rs485_nvic.NVIC_IRQChannel = UART2_IRQn;
    rs485_nvic.NVIC_IRQChannelPriority = 2;
    rs485_nvic.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&rs485_nvic);
	
	UART_ITConfig(RS485_UART_CORE, UART_IT_TC, DISABLE);     
	UART_ITConfig(RS485_UART_CORE, UART_IT_IDLE, ENABLE);
	
	NVIC_InitTypeDef dma_nvic;
	dma_nvic.NVIC_IRQChannel = DMA_Channel4_5_IRQn;
    dma_nvic.NVIC_IRQChannelPriority = 1;
    dma_nvic.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&dma_nvic);
}

void UART2_IRQHandler(void) {
	
	if(UART_GetITStatus(RS485_UART_CORE,UART_IT_IDLE) != RESET) {
		UART_ClearITPendingBit(RS485_UART_CORE,UART_IT_IDLE);

		uint16_t value = UART_ReceiveData(RS485_UART_CORE);		
		uint16_t remain_len = RS485_RXBUFFER_SIZE - (uint16_t)DMA_GetCurrDataCounter(RS485_DMA_RX_CHANNEL);
		DMA_Cmd(RS485_DMA_RX_CHANNEL,DISABLE);
		if(remain_len) {
			if(remain_len > RS485_HALF_RX_BUFFER_SIZE) {
				ring_buffer_put(rs485_ringbuf_recv,rs485_dma_rx_buf + RS485_HALF_RX_BUFFER_SIZE, remain_len - RS485_HALF_RX_BUFFER_SIZE);    /*将数据放入接收缓冲区*/ 
			} else {
				ring_buffer_put(rs485_ringbuf_recv,rs485_dma_rx_buf, remain_len);    /*将数据放入接收缓冲区*/ 
			}
			
									
			BaseType_t ret_val;
			xSemaphoreGiveFromISR(rs485_semap_,&ret_val);
		} else {
		}
		
		// while (DMA_GetCmdStatus(TTY_DMA_RX_CHANNEL) != DISABLE && retry++ < 100){}  
		DMA_SetCurrDataCounter(RS485_DMA_RX_CHANNEL,RS485_RXBUFFER_SIZE);
		DMA_ClearFlag(DMA_FLAG_TC5);
        DMA_Cmd(RS485_DMA_RX_CHANNEL,ENABLE);
	}
		
	if(UART_GetITStatus(RS485_UART_CORE,UART_IT_TC) == SET) {
		//UART_ClearITPendingBit(TTY_UART_CORE,UART_IT_TC);
		int len = ring_buffer_get(rs485_ringbuf_send,rs485_dma_tx_buf,RS485_TXBUFFER_SIZE);
        if (len != 0) {
            DMA_Cmd(RS485_DMA_TX_CHANNEL,DISABLE);
			DMA_ClearFlag(DMA_FLAG_TC4);
            DMA_SetCurrDataCounter(RS485_DMA_TX_CHANNEL, len);
            DMA_Cmd(RS485_DMA_TX_CHANNEL, ENABLE);
			UART_ClearFlag(RS485_UART_CORE, UART_FLAG_TC);
        } else {
			UART_ITConfig(RS485_UART_CORE,UART_IT_TC, DISABLE);
        }
	}
}

void DMA_Channel4_5_IRQHandler() {

	uint8_t flag = 0;

	if(DMA_GetFlagStatus(DMA_FLAG_HT5) != RESET) {
		ring_buffer_put(rs485_ringbuf_recv, rs485_dma_rx_buf, RS485_HALF_RX_BUFFER_SIZE);
		DMA_ClearFlag(DMA_FLAG_HT5);
		flag = 1;
	}
	
	 if(DMA_GetFlagStatus(DMA_FLAG_TC5) != RESET) {
		ring_buffer_put(rs485_ringbuf_recv, rs485_dma_rx_buf + RS485_HALF_RX_BUFFER_SIZE, RS485_HALF_RX_BUFFER_SIZE);
		DMA_ClearFlag(DMA_FLAG_TC5);
		flag = 1;
	 }
	 
	 if(flag) {
		BaseType_t value;
		xSemaphoreGiveFromISR(rs485_semap_,&value);
	 }
}

static void rs485_init() {
	rs485_gpio_init();
	rs485_uart_init();
    rs485_dma_init();
	
	rs485_semap_ = xSemaphoreCreateBinary();
}

static uint16_t rs485_send(void *buf,uint16_t len) {

    int16_t send_len = 0;
    while(send_len < len) {
		send_len += ring_buffer_put(rs485_ringbuf_send, buf + send_len, len - send_len);
		UART_ITConfig(RS485_UART_CORE,UART_IT_TC,ENABLE);
    }
	UART_ClearFlag(RS485_UART_CORE,UART_FLAG_TC);

    return len;
}

static void rs485_tprint(const char *format, ...) {
    va_list args;
    char buf[128] = {0};
    va_start(args, format);
    vsprintf(buf, format, args);       
    va_end(args);    
    rs485_send(buf,strlen(buf));
}

static uint16_t rs485_recv(void *buf, uint16_t len) {
	
	uint16_t data_size = ring_buffer_len(rs485_ringbuf_recv);
	if(data_size > 0) {
		return ring_buffer_get(rs485_ringbuf_recv, (unsigned char *)buf, len);
	} else {
		if(xSemaphoreTake(rs485_semap_,pdMS_TO_TICKS(1000)) == pdTRUE) {
			return ring_buffer_get(rs485_ringbuf_recv, (unsigned char *)buf, len);
		}
	}
	
	return 0;
}

const rs485_t g_rs485_= {
    rs485_init,
    rs485_send,
    rs485_recv,
	rs485_tprint
};
